﻿using System;
using System.Collections.Generic;
using Common;
using Unity.VisualScripting;

namespace FSM
{
    public sealed class FsmManager : IFsmManager
    {
        /// <summary>
        /// 状态机IOC
        /// </summary>
        private readonly Dictionary<TypeNamePair, FsmBase> m_Fsms;
        /// <summary>
        /// 临时列表, 为了迭代安全
        /// </summary>
        private readonly List<FsmBase> m_TempFsms;

        public FsmManager()
        {
            m_Fsms = new Dictionary<TypeNamePair, FsmBase>();
            m_TempFsms = new List<FsmBase>();
        }
        /// <summary>
        /// 获取模块优先级
        /// </summary>
        internal int Priority
        {
            get
            {
                return 1;
            }
        }
        /// <summary>
        /// 获取有限状态机数量
        /// </summary>
        public int Count
        {
            get
            {
                return m_Fsms.Count;
            }
        }
        
        /// <summary>
        /// 有限状态机轮询
        /// </summary>
        /// <param name="elapseSeconds"></param>
        /// <param name="realElapseSeconds"></param>
        internal void Update(float elapseSeconds, float realElapseSeconds)
        {
            m_TempFsms.Clear();
            if (m_Fsms.Count <= 0)
                return;
            //  用临时列表 是为了 迭代安全(iteration safety)
            //  某些状态机可能在这次更新中被标记为“已销毁”（通过 IsDestroyed 判断），
            //  甚至可能触发自身的销毁逻辑（比如从 m_Fsms 中移除自己）
            foreach(KeyValuePair<TypeNamePair, FsmBase> fsm in m_Fsms)
                m_TempFsms.Add(fsm.Value);
            foreach (FsmBase fsm in m_TempFsms)
            {
                if (fsm.IsDestroyed)
                    continue;
                fsm.Update(elapseSeconds, realElapseSeconds);
            }
        }

        /// <summary>
        /// 关闭并清理有限状态机管理器
        /// </summary>
        internal  void Shutdown()
        {
            foreach(KeyValuePair<TypeNamePair, FsmBase> fsm in m_Fsms)
                fsm.Value.Shutdown();
            m_Fsms.Clear();
            m_TempFsms.Clear();
        }

        public bool HasFsm<T>() where T : class
        {
            return InternalHasFsm(new TypeNamePair(typeof(T)));
        }

        public bool HasFsm(Type ownerType)
        {
            if (ownerType == null)
                throw new Exception("Owner type is invalid.");
            return InternalHasFsm(new TypeNamePair(ownerType));
        }
        
        public bool HasFsm<T>(string name) where T : class
        {
            return InternalHasFsm(new TypeNamePair(typeof(T), name));
        }

        public bool HasFsm(Type ownerType, string name)
        {
            if (ownerType == null)
                throw new Exception("Owner type is invalid.");
            return InternalHasFsm(new TypeNamePair(ownerType, name));
        }

        public IFsm<T> GetFsm<T>() where T : class
        {
            return (IFsm<T>)InternalGetFsm(new TypeNamePair(typeof(T)));
        }

        public FsmBase GetFsm(Type ownerType)
        {
            if (ownerType == null)
                throw new Exception("Owner type is invalid.");
            return InternalGetFsm(new TypeNamePair());
        }
        
        public IFsm<T> GetFsm<T>(string name) where T : class
        {
            return (IFsm<T>)InternalGetFsm(new TypeNamePair(typeof(T), name));
        }

        public FsmBase GetFsm(Type ownerType, string name)
        {
            if (ownerType == null)
                throw new Exception("Owner type is invalid.");
            return InternalGetFsm(new TypeNamePair(ownerType, name));
        }


        public FsmBase[] GetAllFsms()
        {
            int index = 0;
            FsmBase[] results = new FsmBase[m_Fsms.Count];
            foreach (KeyValuePair<TypeNamePair, FsmBase> fsm in m_Fsms)
            {
                results[index++] = fsm.Value;
            }

            return results;
        }

        public void GetAllFsms(List<FsmBase> results)
        {
            if (results == null)
                throw new Exception("Results is invalid.");
            results.Clear();
            foreach(KeyValuePair<TypeNamePair, FsmBase> fsm in m_Fsms)
                results.Add(fsm.Value);
        }


        public IFsm<T> CreateFsm<T>(T owner, params FsmState<T>[] states) where T : class
        {
            return CreateFsm(string.Empty, owner, states);
        }

        public IFsm<T> CreateFsm<T>(string name, T owner, params FsmState<T>[] states) where T : class
        {
            TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name);
            if (HasFsm<T>(name))
                throw new Exception(string.Format("Already exist FSM '{0}'", typeNamePair));
            Fsm<T> fsm = Fsm<T>.Create(name, owner, states);
            m_Fsms.Add(typeNamePair, fsm);
            return fsm;
        }
        
        

        public IFsm<T> CreateFsm<T>(T owner, List<FsmState<T>> states) where T : class
        {
            return CreateFsm(string.Empty, owner, states);
        }

        public IFsm<T> CreateFsm<T>(string name, T owner, List<FsmState<T>> states) where T : class
        {
            TypeNamePair typeNamePair = new TypeNamePair(typeof(T), name);
            if (HasFsm<T>(name))
                throw new Exception(string.Format("Already exist FSM '{0}'", typeNamePair));
            Fsm<T> fsm = Fsm<T>.Create(name, owner, states);
            m_Fsms.Add(typeNamePair, fsm);
            return fsm;
        }
        /// <summary>
        /// 销毁有限状态机
        /// </summary>
        /// <typeparam name="T">状态机持有者</typeparam>
        /// <returns></returns>
        public bool DestroyFsm<T>() where T : class
        {
            return InternalDestroyFsm(new TypeNamePair(typeof(T)));
        }
        
        public bool DestroyFsm<T>(string name) where T : class
        {
            return InternalDestroyFsm(new TypeNamePair(typeof(T), name));
        }
        
        public bool DestroyFsm(Type ownerType)
        {
            if (ownerType == null)
                throw new Exception("Owner type is invalid.");
            return InternalDestroyFsm(new TypeNamePair(ownerType));
        }

        public bool DestroyFsm(Type ownerType, string name)
        {
            if (ownerType == null)
                throw new Exception("Owner type is invalid.");
            return InternalDestroyFsm(new TypeNamePair(ownerType, name));
        }

        public bool DestroyFsm<T>(IFsm<T> fsm) where T : class
        {
            if (fsm == null)
                throw new Exception("FSM is invalid.");
            return InternalDestroyFsm(new TypeNamePair(typeof(T), fsm.Name));
        }

        public bool DestroyFsm(FsmBase fsm)
        {
            if (fsm == null)
                throw new Exception("FSM is invalid.");
            return InternalDestroyFsm(new TypeNamePair(fsm.OwnerType, fsm.Name));
        }
        
        

        private bool InternalHasFsm(TypeNamePair typeNamePair)
        {
            return m_Fsms.ContainsKey(typeNamePair);
        }

        private FsmBase InternalGetFsm(TypeNamePair typeNamePair)
        {
            FsmBase fsm = null;
            if (m_Fsms.TryGetValue(typeNamePair, out fsm))
                return fsm;
            return null;
        }

        private bool InternalDestroyFsm(TypeNamePair typeNamePair)
        {
            FsmBase fsm = null;
            if (m_Fsms.TryGetValue(typeNamePair, out fsm))
            {
                fsm.Shutdown();
                return m_Fsms.Remove(typeNamePair);
            }

            return false;
        }

    }
}